/*
 
 hehe based on this code >>
 flemme de faire tout donc j'ai repris la base pour création socket,
 init et listen ;) 
 ECHOSERV.C
 ==========
 (c) Paul Griffiths, 1999
 Email: mail@paulgriffiths.net
 
 Simple TCP/IP echo server.
 
 */


#import <Foundation/Foundation.h>
#import <ApplicationServices/ApplicationServices.h>


#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

#define LISTEN_PORT          20007
#define TIMEOUTVAL 30

unsigned long int timeval_subtract(struct timeval *t2, struct timeval *t1){
	return (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec);
}
struct timeval beg;

int numberClick(){
	struct timeval actual;
	gettimeofday(&actual, NULL);
	if(timeval_subtract(&actual, &beg)<500000){
		gettimeofday(&beg, NULL);
		return 2;
	}
	gettimeofday(&beg, NULL);
	return 1;
}


CGEventRef event;
CGPoint offset;
CGPoint currentLocation;
CGPoint newLocation;
int x=-1;
int y=-1;

void command_handle(int cmd, int data1, int data2){

	if(cmd == 3 || x==-1 || y==-1){
		event = CGEventCreate(NULL);
		currentLocation = CGEventGetLocation(event);
		CFRelease(event);
		
		x = data1;
		y = data2;
	}else if(cmd == 5 || cmd == 6){
		event = CGEventCreate(NULL);
		currentLocation = CGEventGetLocation(event);
		CFRelease(event);
		
		
		event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 20, cmd == 5 ? 25 : -25);
		CGEventSetType(event, kCGEventScrollWheel);
		CGEventPost(kCGHIDEventTap, event);
		CFRelease(event);
		
		x = -1;
		y = -1;
	}else if(cmd == 4){
		event = CGEventCreate(NULL);
		currentLocation = CGEventGetLocation(event);
		CFRelease(event);
		event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, currentLocation, 
																		kCGMouseButtonLeft);
		CGEventSetIntegerValueField(event, kCGMouseEventClickState, numberClick());
		
		CGEventPost(kCGHIDEventTap, event);
		CFRelease(event);
		
		event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, currentLocation, 
																		kCGMouseButtonLeft);
		CGEventPost(kCGHIDEventTap, event);
		CFRelease(event);
		
		
		x = data1;
		y = data2;
	}else{
		if(data1-x < 200 && data2-y < 200 &&
			 currentLocation.x+data1-x > 0 && 
			 currentLocation.y+data2-y > 0){
			event = CGEventCreate(NULL);
			currentLocation = CGEventGetLocation(event);
			CFRelease(event);
			
			offset = CGPointMake(data1-x,data2-y);
			newLocation = CGPointMake(currentLocation.x + offset.x, currentLocation.y + offset.y);
			currentLocation.x+=offset.x;
			currentLocation.y+=offset.y;
			
			event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, currentLocation, kCGMouseButtonLeft);
			CGEventPost(kCGHIDEventTap, event);
			CFRelease(event);
			
			x = data1;
			y = data2;
		}
	}
}

int main(int argc, char *argv[]) {
	gettimeofday(&beg, NULL);
	
  NSUserDefaults *args = [NSUserDefaults standardUserDefaults];

	struct timeval _timeout;
	
	int       list_s;                /*  listening socket          */
	int       conn_s;                /*  connection socket         */
	short int port;                  /*  port number               */
	struct    sockaddr_in servaddr;  /*  socket address structure  */
	
	int coords[3];
	int on = 1;
	
	port = LISTEN_PORT;
	printf("listening on the %d port\n", LISTEN_PORT);
	
	if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		fprintf(stderr, "Coudl not create!\n");
		exit(EXIT_FAILURE);
	}
	setsockopt(list_s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
	
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port        = htons(port);
	
	
	if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
		fprintf(stderr, "Error bind()\n");
		exit(EXIT_FAILURE);
	}
	
	if ( listen(list_s, 5) < 0 ) {
		fprintf(stderr, "Error listen()\n");
		exit(EXIT_FAILURE);
	}
	
	
	int error=0;
	while ( 1 ) {
		error=0;
		
		if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
	    printf("ECHOSERV: Error calling accept()\n");
		}else{
	    printf("client \\o/\n");
		}
		
		
		/*  Retrieve an input line from the connected socket
		 then simply write it back to the same socket.     */
		/*
		 2 > move
		 3 > up/restore
		 4 > click
		 5 > scroll up
		 6 > scroll down
		 */
		while(error >= 0){
			fd_set read_sd;
			FD_ZERO(&read_sd);
			FD_SET(conn_s, &read_sd);
			
      fd_set rsd = read_sd;
			memset(&_timeout, 0, sizeof(_timeout));
			_timeout.tv_sec=TIMEOUTVAL;
	      int sel = select(conn_s + 1, &rsd, 0, 0, &_timeout);
      if (sel > 0){
				error = read(conn_s, &(coords[0]), sizeof(int));
				coords[0] = ntohl(coords[0]);
				if(error==sizeof(int)){
					if(coords[0]==2 || coords[0]==3 || coords[0]==4 || coords[0]==5|| coords[0]==6){
						error = read(conn_s, &(coords[1]), sizeof(int));
						coords[1] = ntohl(coords[1]);
						error = read(conn_s, &(coords[2]), sizeof(int));
						coords[2] = ntohl(coords[2]);
						command_handle(coords[0], coords[1], coords[2]);
						
					}else
						error = -1; //we received an invalid command
				}else
					error = -1; // we received an invalid size of data
			}else
				error = -1; // we did not receive any data 
		}
		
		
		if(close(conn_s) < 0){
	    fprintf(stderr, "close() error \n");
		}
	}
}
